package game;

import java.util.ArrayList;
import java.util.HashSet;

import command.PiecePlaceCommand;

import chess.Player;
import chess.QueenPiece;
import chess.Tile;
/**
 * This class is the eight queens game class. It will play out a full game of eight queens. 
 * This game allows you to add pieces and remove pieces. The game is only won when all eight queens
 * have been placed on the board.
 * 
 * @author Samual Martelli, Caleb Chan
 */
public class EightQueensGame extends Game {
	private PiecePlaceCommand listOfQueens[];
	private int numberOfQueens;
	private Player singlePlayer;
	public static final String EIGHT_QUEENS_GAME_PLAYER_NAME = "Player 1";
	public static final String PLAYER_COLOR = "White";
	public static final int MAX_NUMBER_OF_QUEENS = 8;

	private MoveExecutionList pastList;
	public EightQueensGame() {
		singlePlayer = new Player(EIGHT_QUEENS_GAME_PLAYER_NAME, this,PLAYER_COLOR);
		listOfQueens = new PiecePlaceCommand[8];
		listOfMoves = new MoveExecutionList();
		numberOfQueens = 0;
	}
	public EightQueensGame(Player p){
		singlePlayer = p;
		listOfQueens = new PiecePlaceCommand[MAX_NUMBER_OF_QUEENS];
		numberOfQueens = 0;
	}
	/**
	 * These getters and setters will allow easier access 
	 * for the  Eight Queens junit testing
	 *  <pre>
	 * Samual Martelli
	 * -Creation (Feb 3,2010)
	 * </pre>
	 */
	public Tile[] getlistOfQueens() {
		Tile[] t = new Tile[MAX_NUMBER_OF_QUEENS];
		for(int i = 0; i < numberOfQueens; i++){
			t[i] = listOfQueens[i].getCurrentTile();
		}
		return t;
	}
	/**
	 * This method will return the number of queens that have been placed on the board
	 * @return Returns the number of queens
	 */
	public int getnumberOfQueens() {
		return this.numberOfQueens;
	}
	/**
	 * This method will set queens on the tile given as a parameter. The number of queens
	 * must be set first before this method can be called
	 * @param t The tiles for queens to be set
	 */
	public void setlistOfQueens(Tile[] t) {
		listOfQueens = new PiecePlaceCommand[MAX_NUMBER_OF_QUEENS];
		for(int i = 0; i < numberOfQueens; i++){
			listOfQueens[i] = new PiecePlaceCommand(t[i],"Queen",singlePlayer);
		}
	}
	/**
	 * This set the number of queens on the board
	 * @param totalQueens The number of queens to be set
	 */
	public void setnumberOfQueens(int totalQueens) {
		this.numberOfQueens = totalQueens;
	}
	@Override
	/**
	 * This class method will implement the startup method 
	 * for the game Eight Queens
	 *  <pre>
	 * Samual Martelli
	 * -Creation (Jan 22,2010)
	 * </pre>
	 */
	public void startup() {
		this.getBoard().drawBoard();
	}
	/**
	 * This will returns the a list of moves that represent the places that queens
	 * have been placed
	 * @return Returns a list of moves for the queens that have been placed
	 */
	@Override
	public MoveExecutionList getMoveExecutionList(){
		listOfMoves = new MoveExecutionList();
		for(int i = 0; i < numberOfQueens; i++){
			listOfMoves.add(listOfQueens[i]);
		}
		return listOfMoves;
	}
	/**
	 * This lets a (human) player take a turn
	 * 
	 * <pre>
	 * Max Joyce
	 * -Creation (Feb 9, 2010)
	 * </pre>
	 */	
	public void takeTurn(Player p){
		Tile selectedTile = null;
		// Loops until a tile that doesn't have a piece is chosen
		selectedTile = chooseTile();
		if(selectedTile == null){
			return;
		}
		if(selectedTile.isPieceHere()){
			removePiece(selectedTile);
		}else{
			listOfQueens[numberOfQueens] = new PiecePlaceCommand(selectedTile,"Queen",singlePlayer);
			if(!isValidMove()){
				listOfQueens[numberOfQueens] = null;
				this.view.showOutputMessage("Invalid Move");
			}else{
				selectedTile.setPieceHere(new QueenPiece(singlePlayer,selectedTile));
				listOfQueens[numberOfQueens] = new PiecePlaceCommand(selectedTile,"Queen",singlePlayer);
				numberOfQueens++;
			}
		}
	}
	
	/**
	 * This method will run all the functions of the Eight Queens Game
	 * <pre>
	 * Caleb Chan
	 * -Creation (Jan 23, 2010)
	 * </pre>
	 */
	public void play(){
		boolean endGame = false;
		while(!endGame &&!isNewGame){
			this.singlePlayer.takeTurn();
			this.view.printlnToDebugConsole("- - - - - - - - -");
			super.getBoard().drawBoard();
			
			endGame = endGameConditions();
		}
		if(!isNewGame){
			endGameMessage();
		}
	}
	/**
	 * This method removes a the queen from a selected tile. If the selected tile is null,
	 * the method will exit without removing the queen from the board
	 * <pre>
	 * Caleb Chan
	 * -Created Jan 28, 2010
	 * </pre>
	 * @param selectedRemoveTile The tile containing the queen to be removed
	 */
	public void removePiece(Tile selectedRemoveTile){
		if(selectedRemoveTile == null){
			return;
		}
		int i = 0;
		for(; i < numberOfQueens; i++){
			if(listOfQueens[i].getCurrentTile().equals(selectedRemoveTile)){
				listOfQueens[i].undo();
				listOfQueens[i] = null;
				break;
			}
		}
		for(;i < listOfQueens.length - 1;i++){
			listOfQueens[i] = listOfQueens[i + 1];
		}
		listOfQueens[listOfQueens.length - 1] = null;
		numberOfQueens--;
	}
	/**
	 * Check if the condition for the end of the game has been met
	 * If the condition is met, it will return true.
	 * For the Eight Queens, it will return true if there are 8 queens one the board
	 * <pre>
	 * Caleb Chan
	 * -Created (Jan 24, 2010)
	 * </pre>
	 * @return Returns true if the end game conditions are met
	 */
	private boolean endGameConditions(){
		return numberOfQueens == MAX_NUMBER_OF_QUEENS;
	}
	/**
	 * Displays the end of the game message
	 * <pre>
	 * Caleb Chan
	 * -Created (Jan 24, 2010)
	 * </pre>
	 */
	private void endGameMessage(){
		this.view.showOutputMessage("You Have Won The Game !!!");
	}
	/**
	 * This method will check if the new piece that has been added is in conflict with
	 * other pieces
	 * <pre>
	 * Caleb Chan
	 * -Creation (Jan 23, 2010)
	 * <pre>
	 * @return	Returns a boolean true value if the move is valid
	 */
	public boolean isValidMove(){
		HashSet<Tile> moves = new HashSet<Tile>();
		for(int i = 0; i < numberOfQueens;i++){
			System.out.println("List Of : " + listOfQueens[i].toString());
			System.out.println("List Of : " + listOfQueens[i].getCurrentTile().toString());
			moves.addAll(listOfQueens[i].getCurrentTile().getPieceHere().getMovementTiles());
		}
		return !moves.contains(listOfQueens[numberOfQueens].getCurrentTile());
	}
	/**
	 * This will enact all task that need to be done before a new game can be created
	 */
	public void newGameSelected(){
		isNewGame = true;
	}
	/**
	 * This method will redo actions in the game. Currently it has not been created because
	 * of the addition of clicking on a piece to remove it from the board.
	 */
	public void redo(){
		if(listOfMoves.redo()){
			view.displayBoard();
		}
		
	}
	/**
	 * This method will undo actions in the game. Currently it has not been created because
	 * of the addition of clicking on a piece to remove it from the board.
	 */
	public void undo(){
		if(listOfMoves.undo()){
			view.displayBoard();
		}
		
	}
	/**
	 * This will set the player by the index. 
	 * @param player The index of the player in the current list of players
	 */
	@Override
	public void setPlayer(int player) {
	}
	/**
	 * This method will reset the board to the start position
	 * <pre>
	 * Caleb Chan
	 * </pre>
	 */
	@Override
	public void resetBoard(){
		pastList = getMoveExecutionList();
		System.out.println("List 2 : \n" + pastList.toString());
		for(int i = 0; i < numberOfQueens; i++){
			removePiece(listOfQueens[i].getCurrentTile());
		}
	}
	@Override
	public void restoreBoard(){
		listOfQueens = new PiecePlaceCommand[MAX_NUMBER_OF_QUEENS];
		singlePlayer.resetMyPieces();
		for(int i = 0; i < pastList.size(); i++){
			listOfQueens[i] = (PiecePlaceCommand)pastList.get(i);
			listOfQueens[i].execute();
		}
		setnumberOfQueens(pastList.size());
	}
	/**
	 * This method will set the list of moves and it is used when importing a move list. 
	 * If the board has a game currently active, it will reset the board.
	 * @param list The move list that is being replaced
	 * <pre>
	 * Caleb Chan
	 * </pre>
	 */
	@Override
	public void setMoveList(MoveExecutionList list){
		resetBoard();
		listOfQueens = new PiecePlaceCommand[MAX_NUMBER_OF_QUEENS];
		for(int i = 0; i < list.size(); i++){
			listOfQueens[i] = (PiecePlaceCommand)list.get(i);
		}
		setnumberOfQueens(list.size());
	}
	/**
	 * This method will get the players in the game
	 * @return Returns a list of players
	 */
	@Override
	public ArrayList<Player> getPlayers() {
		ArrayList<Player> players = new ArrayList<Player>();
		players.add(singlePlayer);
		return players;
	}
}
